<?php

namespace App\Kuafu\Guanyuan\Command;

use App\Kuafu\Base\Command\Traits\KfGetTimeInterval;
use App\Kuafu\Category\Model\CategoryModel;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\Guanyuan\Enum\DishDetailEnum;
use App\Kuafu\Guanyuan\Model\DishDetailCHModel;
use App\Kuafu\Guanyuan\Model\DishDetailModel;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderDetailSplitModel;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Shop\Model\Shop;
use App\Library\FeiShu\SendFs;
use App\Library\SnowFlake\SnowFlake;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;

class OrderDishDetailCommand extends Command
{
    use KfGetTimeInterval;

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'guanyuan:kfSyncDishDetail 
    {--d=false :  是否直接执行 示例.true - 默认执行前一天数据 false - 交互式执行}
    {--shopIds= :  手动执行的 shopIds}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '观远订单同步:堂食菜品数据';

    /**
     * @var bool 判断是否写入 ck 数据库
     */
    protected bool $isInCkDb = true;

    /**
     * @var int Ck 报错次数
     */
    protected int $errCkDbNum = 0;

    /**
     * Execute the console command
     */
    public function handle()
    {
        // qa 环境关闭运行
        if (isTest()) {
            return false;
        }

        $this->infoTime('执行时间 开始');
        ini_set('memory_limit', '2048M');
        list($startTimeAt, $endTimeAt) = $this->getTimeInterval();

        $this->info('**************** 开始执行脚本 ****************');
        $this->info(vsprintf(
            '起始时间 [ %s ] 截止时间 [ %s ]',
            [date('Y-m-d H:i:s', $startTimeAt), date('Y-m-d H:i:s', $endTimeAt)]
        ));

        $skipShopList = [13315]; // 跳过的 店铺id

        // 获取所有店铺信息
        $shopList = Shop::query()
                        ->get()
                        ->keyBy('id')
                        ->each(function ($item) {
                            // 处理省市区
                            $ssq = explode('-', $item['addressPrefix']);
                            if (empty($ssq)
                                || empty($ssq[0])
                                || empty($ssq[1])
                                || empty($ssq[2])
                            ) {
                                return;
                            }
                            $item['province'] = $ssq[0];
                            $item['city']     = $ssq[1];
                            $item['district'] = $ssq[2];

                        })
                        ->toArray();

        $this->infoTime('执行时间 获取店铺信息');

        $manualShopIds = $this->option('shopIds');
        if (!$manualShopIds) {
            $inShopList = Shop::getGyShopList()->pluck('name', 'id')->toArray();
        } else {
            // 手动执行
            $inShopList = explode(",", $manualShopIds);
            $inShopList = array_flip($inShopList);
        }

        $resultFs  = [];
        $queryDate = [];
        $diff      = ($endTimeAt - $startTimeAt) / 86400;

        for ($d = 1; $d <= $diff; $d++) {
            $queryDate[] = [
                'startTime' => $startTimeAt + 86400 * ($d - 1),
                'endTime'   => $startTimeAt + 86400 * $d
            ];
        }

        $this->infoTime('执行点 1');
        foreach ($queryDate as $date) {
            $fsMsg = '';
            foreach ($inShopList as $shopId => $shopName) {
                // 判断是否数据库中有数据如果有数据 则 不删除
                $order = OrderSplitModel::suffix($shopId)
                                        ->query()
                                        ->where('shopId', $shopId)
                                        ->whereBetween('createdAt', [$date['startTime'], $date['endTime']])
                                        ->whereNotIn('shopId', $skipShopList)
                                        ->where('payStatus', CodeEnum::ORDER_PAY_STATUS_PAYED)
                                        ->whereIn('orderStatus', [CodeEnum::ORDER_STATUS_FINISHED])
                                        ->where('isDeleted', 0)
                                        ->get();
                $this->infoTime('执行点 2');

                if ($order->count() == 0) {
                    continue;
                }

                // 删除数据
                DishDetailModel::query()
                               ->where('checkoutTime', '>=', date('Y-m-d H:i:s', $date['startTime']))
                               ->where('checkoutTime', '<=', date('Y-m-d H:i:s', $date['endTime']))
                               ->where('source', DishDetailEnum::SOURCE_KUAFU)
                               ->where("poiName", "like",
                                   CommonService::zeroFill($shopList[$shopId]['shopCode']) . "%")
                               ->delete();

                if ($this->isInCkDb) {
                    try {
                        DishDetailCHModel::query()
                                         ->where('checkoutTime', '>=', date('Y-m-d H:i:s', $date['startTime']))
                                         ->where('checkoutTime', '<=', date('Y-m-d H:i:s', $date['endTime']))
                                         ->where('source', DishDetailEnum::SOURCE_KUAFU)
                                         ->where("poiName", 'LIKE',
                                             CommonService::zeroFill($shopList[$shopId]['shopCode']) . "%")
                                         ->delete();
                    } catch (\Exception $exception) {
                        $this->errCkDbNum++;
                        if ($this->errCkDbNum > 3) {
                            $this->isInCkDb = false;
                            self::sendFs('堂食 ck 的数据异常,已经停止入 ck 数据库', ['3fgc8798']);
                        }
                    }
                }


                $this->infoTime('执行点 3');

                $fsMsg .= CommonService::zeroFill($shopList[$shopId]['shopCode']) .
                    $shopList[$shopId]['name'] . '在' . date('Y-m-d H:i:s',
                        $date['startTime']) . ' 至 ' . date('Y-m-d H:i:s',
                        $date['endTime']) . "的堂食数据已被删除 \r\n";

                // 获取所有原订单数据

                $orderIds      = $order->pluck('orderId');
                $orderListById = $order->keyBy('orderId')->toArray();
                // 获取所有原订单菜品详情
                $orderDetail     = OrderDetailSplitModel::suffix($shopId)
                                                        ->query()
                                                        ->whereIn('orderId', $orderIds)
                                                        ->where('refundNum', 0)
                                                        ->where('isDeleted', 0)
                                                        ->where('packageId', 0)
                                                        ->get();
                $orderDetailById = $orderDetail->toArray();
                // 获取所有优惠券信息
                $orderCouponList     = OrderCouponSplitModel::suffix($shopId)
                                                            ->query()
                                                            ->whereIn('orderId', $orderIds)
                                                            ->where('isDeleted', 0)
                                                            ->get();
                $orderCouponListById = $orderCouponList->toArray();

                $insertData = [];

                $this->infoTime('执行点 3-1');
                foreach ($orderDetailById as $detail) {
                    $orderInfo = $orderListById[$detail['orderId']];
                    $insert    = [
                        'province'       => $shopList[$detail['shopId']]['province'],
                        'city'           => $shopList[$detail['shopId']]['city'],
                        'district'       => $shopList[$detail['shopId']]['district'],
                        'poiName'        => CommonService::zeroFill($shopList[$detail['shopId']]['shopCode']) . $shopList[$detail['shopId']]['name'],
                        'spuId'          => $detail['productId'],
                        'spuName'        => $detail['productName'],
                        'specs'          => '',
                        'unit'           => $detail['unit'],
                        'firstCateName'  => $this->getCategoryName($detail['categoryId']),
                        'orderNo'        => $detail['orderId'],
                        'orderId'        => $detail['orderId'],
                        'count'          => $detail['num'],
                        'totalPrice'     => $detail['originalPrice'] / 100,
                        'discountAmount' => ($detail['totalDiscountPrice'] - $detail['couponCostPrice']) / 100,
                        'taxExcludedAmt' => ($detail['payPrice'] + $detail['couponCostPrice']) / 100,
                        'goodsTime'      => $detail['createdAt'],
                        'orderTime'      => $orderInfo['createdAt'],
                        'checkoutTime'   => date('Y-m-d H:i:s', $orderInfo['completeTime']),
                        'categoryName'   => '店内销售',
                        'sourceName'     => $this->switchSourceName($orderInfo['sourceType']), // 小程序等
                        'orderPrice'     => $orderInfo['originalPrice'] / 100, //订单原价
                        'orderDiscount'  => ($orderInfo['discountPrice'] - $orderInfo['couponCostPrice']) / 100, //订单优惠
                        'orderIncome'    => ($orderInfo['payPrice'] + $orderInfo['couponCostPrice']) / 100, // 订单实收
                        'flagName'       => '',
                        'createdAt'      => date('Y-m-d H:i:s'),
                        'updatedAt'      => date('Y-m-d H:i:s'),
                        'discountName'   => '',
                        'source'         => 1,
                        'dataFrom'       => 'kuafu',
                    ];

                    // 如果有订单优惠 去查订单优惠表记录
                    $discountName = '';
                    if ($insert['orderDiscount'] > 0) {
                        $discountName = '';

                        // 先看订单是否是试吃
                        if ($orderInfo['payChannel'] == CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                            $discountName .= '自定义记账-试吃(自),';
                        }

                        // 是否赠菜
                        if ($detail['freeNum'] > 0) {
                            $discountName .= '自定义记账-赠菜(自),';
                        }

                        // 是否减免
                        if ($detail['discountType'] > 0) {
                            $discountName .= '自定义记账-' . CodeEnum::DISCOUNT_TYPE_TEXT[$detail['discountType']] . '(自),';
                        }

                        // 循环获取优惠券信息
                        foreach ($orderCouponListById as $key => $orderCoupon) {
                            if ($orderCoupon['orderId'] == $detail['orderId']) {
                                $discountName .= '优惠券-' . $orderCoupon['couponName'] . ';';
                            }
                        }
                        $discountName = trim($discountName, ',');
                    }
                    $insert['discountName'] = $discountName;
                    $insertData[]           = $insert;
                }
                $this->infoTime('执行点 4');

                $resultFs[$shopId][date('Y-m-d', $date['startTime'])] = [
                    'shopName' => CommonService::zeroFill($shopList[$shopId]['shopCode']) . $shopList[$shopId]['name']
                ];

                collect($insertData)->chunk(1000)->each(function ($item) {
                    try {
                        $insertData = $item->toArray();
                        foreach ($insertData as &$datum) {
                            $datum['id'] = SnowFlake::nextIdCache();
                        }
                        $insertData = array_values($insertData);
                        DishDetailModel::query()->insert($insertData);
                        if ($this->isInCkDb) {
                            DishDetailCHModel::query()->insert($insertData);
                        }
                    } catch (\Exception $exception) {
                        self::sendFs('Clickhouse 写入数据异常', ['3fgc8798']);
                    }
                });

                $this->infoTime('执行点 5');

                $this->info($shopId . ' - ' . $shopList[$shopId]['name'] . '于' . date('Y-m-d',
                        $date['startTime']) . "数据已经导入");
            }
            self::sendFs($fsMsg);
            $this->infoTime('执行点 6');
        }

        // 组装飞书数据
        $content = date('Y-m-d H:i:s',
                $startTimeAt) . ' 至 ' . date('Y-m-d H:i:s',
                $endTimeAt - 1) . ' 数据已经入库至观远, 耗时' . (microtime(true) - LARAVEL_START) . '秒';

        $content .= "\r\n" . '门店数据如下:' . "\r\n";
        $content .= '日期' . str_pad('', 28) . '店名' . "\r\n";

        foreach ($resultFs as $key => $result) {
            foreach ($result as $date => $shopInfo) {
                $content .= $date . str_pad('', 10) . str_pad($shopInfo['shopName'], 56) . PHP_EOL;
            }
        }
        self::sendFs($content);
    }

    public static $allCategory = null;

    private function getAllCategory()
    {
        if (!self::$allCategory) {
            self::$allCategory = CategoryModel::query()->select(['id', 'pid', 'name'])->get()->keyBy('id')->toArray();
        }
        return self::$allCategory;
    }

    private function getCategoryName($id)
    {
        $list = $this->getAllCategory();
        if (key_exists($id, $list)) {
            return $list[$id]['name'];
        } else {
            return '';
        }
    }

    private function switchSourceName($sourceType)
    {
        switch ($sourceType) {
            case 1:
                return '收银POS';
            case 2:
                return '小程序';
            default:
                return '';
        }
    }

    private static function sendFs($content, $fsUid = [])
    {
        if (!empty($content)) {
            SendFs::newRobot(SendFs::ROBOT_GUANYUAN)
                  ->setTitleContent('[堂食] ' . date('Y-m-d H:i:s', time()), $content)
                  ->setAtUids($fsUid)
                  ->send();
        }
    }

    public function infoTime(string $tag)
    {
        $this->info($tag . ' : ' . (microtime(true) - LARAVEL_START));
    }

}
